package com.opencee.cloud.base.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.opencee.boot.db.mybatis.service.impl.SupperServiceImpl;
import com.opencee.cloud.base.constants.BaseConstants;
import com.opencee.cloud.base.entity.BaseOrganizationEntity;
import com.opencee.cloud.base.entity.BaseUserEntity;
import com.opencee.cloud.base.mapper.BaseOrganizationMapper;
import com.opencee.cloud.base.service.IBaseOrganizationService;
import com.opencee.cloud.base.service.IBaseOrganizationUserService;
import com.opencee.cloud.base.service.IBaseUserService;
import com.opencee.cloud.base.vo.BaseOrganizationVO;
import com.opencee.common.exception.BaseFailException;
import com.opencee.common.utils.RedisTemplateUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 组织机构 服务实现类
 * </p>
 *
 * @author liuyadu
 * @since 2021-04-16
 */
@Service
public class BaseOrganizationServiceImpl<removeById> extends SupperServiceImpl<BaseOrganizationMapper, BaseOrganizationEntity> implements IBaseOrganizationService {
    @Autowired
    private RedisTemplateUtil redisTemplateUtil;
    @Autowired
    private IBaseOrganizationUserService organizationUserService;
    @Autowired
    private IBaseUserService userService;

    /**
     * 根据主键查询
     *
     * @param id
     * @return
     */
    @Override
    public BaseOrganizationVO get(Long id) {
        String key = BaseConstants.CACHE_ORG_ID + id;
        if (redisTemplateUtil.hasKey(key)) {
            BaseOrganizationEntity entity = (BaseOrganizationEntity) redisTemplateUtil.get(key);
            return buildOrganizationVo(entity);
        }
        BaseOrganizationEntity entity = super.getById(id);
        if (entity != null) {
            redisTemplateUtil.set(key, entity);
        } else {
            redisTemplateUtil.set(key, entity, 1, TimeUnit.MINUTES);
        }
        return buildOrganizationVo(entity);
    }

    /**
     * 根据组织编码查询角色
     *
     * @param code
     * @return
     */
    @Override
    public BaseOrganizationVO getByCode(String code) {
        String key = BaseConstants.CACHE_ORG_CODE + code;
        if (redisTemplateUtil.hasKey(key)) {
            BaseOrganizationEntity entity = (BaseOrganizationEntity) redisTemplateUtil.get(key);
            return buildOrganizationVo(entity);
        }
        QueryWrapper<BaseOrganizationEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(BaseOrganizationEntity::getCode, code);
        BaseOrganizationEntity entity = super.getOne(queryWrapper);
        if (entity != null) {
            redisTemplateUtil.set(key, entity);
        } else {
            redisTemplateUtil.set(key, entity, 1, TimeUnit.MINUTES);
        }
        return buildOrganizationVo(entity);
    }


    /**
     * 保存
     *
     * @param entity
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean save(BaseOrganizationEntity entity) {
        if (exists(entity.getCode())) {
            throw new BaseFailException(String.format("编码(%s)已存在!", entity.getCode()));
        }
        entity.setCreateTime(new Date());
        entity.setUpdateTime(entity.getCreateTime());
        boolean flag = super.save(entity);
        if (flag) {
            // 设置缓存
            String codeKey = BaseConstants.CACHE_ORG_CODE + entity.getCode();
            String idKey = BaseConstants.CACHE_ORG_ID + entity.getId();
            redisTemplateUtil.set(codeKey, entity);
            redisTemplateUtil.set(idKey, entity);
        }
        return flag;
    }

    /**
     * 修改
     *
     * @param entity
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateById(BaseOrganizationEntity entity) {
        BaseOrganizationEntity saved = getById(entity.getId());
        if (saved == null) {
            throw new BaseFailException(String.format("项目不存在!"));
        }
        if (!saved.getCode().equals(entity.getCode())) {
            // 和原来不一致重新检查唯一性
            if (exists(entity.getCode())) {
                throw new BaseFailException(String.format("编码(%s)已存在!", entity.getCode()));
            }
        }
        entity.setUpdateTime(new Date());
        boolean flag = super.updateById(entity);
        if (flag) {
            // 移除缓存
            String codeKey = BaseConstants.CACHE_ORG_CODE + saved.getCode();
            String idKey = BaseConstants.CACHE_ORG_ID + saved.getId();
            redisTemplateUtil.del(codeKey, idKey);
        }
        return flag;
    }

    /**
     * 查询当前组织id和所有下级组织列表
     *
     * @param id
     * @return
     */
    @Override
    public List<BaseOrganizationVO> listSelfWithSubById(Long id) {
        List<BaseOrganizationVO> list = new ArrayList<>();
        BaseOrganizationEntity entity = super.getById(id);
        if (entity == null || (entity != null && entity.getStatus() != 1)) {
            return list;
        }
        BaseOrganizationVO vo = new BaseOrganizationVO();
        BeanUtil.copyProperties(entity, vo);
        list.add(vo);
        list.addAll(listSubById(id));
        return list;
    }

    /**
     * 根据当前组织id查询所有下级组织列表
     *
     * @param id
     * @return
     */
    @Override
    public List<BaseOrganizationVO> listSubById(Long id) {
        //根据当前部门id查询所有子部门的id
        List<BaseOrganizationVO> recordList = new ArrayList<>();
        List<BaseOrganizationVO> list = baseMapper.selectSubByParentId(id);
        recordList.addAll(list);
        list.forEach(t -> {
            recordList.addAll(listSubById(t.getId()));
        });
        return recordList;
    }

    /**
     * 检测组织编码是否存在
     *
     * @param code
     * @return
     */
    @Override
    public boolean exists(String code) {
        QueryWrapper<BaseOrganizationEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(BaseOrganizationEntity::getCode, code);
        return count(queryWrapper) > 0;
    }

    /**
     * 查询部门列表
     *
     * @param entity
     * @return
     */
    @Override
    public List<BaseOrganizationVO> list(BaseOrganizationEntity entity) {
        QueryWrapper<BaseOrganizationEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .like(ObjectUtils.isNotEmpty(entity.getName()), BaseOrganizationEntity::getName, entity.getName())
                .eq(ObjectUtils.isNotEmpty(entity.getCode()), BaseOrganizationEntity::getCode, entity.getCode())
                .eq(ObjectUtils.isNotEmpty(entity.getHeadUserId()), BaseOrganizationEntity::getHeadUserId, entity.getHeadUserId())
                .eq(ObjectUtils.isNotEmpty(entity.getParentId()), BaseOrganizationEntity::getParentId, entity.getParentId())
                .eq(ObjectUtils.isNotEmpty(entity.getType()), BaseOrganizationEntity::getType, entity.getType())
                .eq(ObjectUtils.isNotEmpty(entity.getStatus()), BaseOrganizationEntity::getStatus, entity.getStatus())
        .orderByDesc(BaseOrganizationEntity::getSort);
        List<BaseOrganizationEntity> list = super.list(queryWrapper);
        return buildOrganizationVoList(list);
    }


    /**
     * 根据名称模糊查询
     *
     * @param keyword
     * @return
     */
    @Override
    public List<BaseOrganizationVO> listByKeyword(String keyword) {
        QueryWrapper<BaseOrganizationEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .like(BaseOrganizationEntity::getName, keyword)
                .or()
                .like(BaseOrganizationEntity::getCode, keyword)
                .orderByDesc(BaseOrganizationEntity::getSort);
        List<BaseOrganizationEntity> list = super.list(queryWrapper);
        return buildOrganizationVoList(list);
    }

    /**
     * 批量id查询
     *
     * @param ids
     * @return
     */
    @Override
    public List<BaseOrganizationVO> listById(Set<Long> ids) {
        QueryWrapper<BaseOrganizationEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().in(BaseOrganizationEntity::getId, ids)
                .orderByDesc(BaseOrganizationEntity::getSort);
        List<BaseOrganizationEntity> list = super.list(queryWrapper);
        return buildOrganizationVoList(list);
    }

    /**
     * 批量code查询
     *
     * @param codes
     * @return
     */
    @Override
    public List<BaseOrganizationVO> listByCode(Set<String> codes) {
        QueryWrapper<BaseOrganizationEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().in(BaseOrganizationEntity::getCode, codes)
                .orderByDesc(BaseOrganizationEntity::getSort);
        List<BaseOrganizationEntity> list = super.list(queryWrapper);
        return buildOrganizationVoList(list);
    }

    /**
     * 批量id查询转map
     *
     * @param ids
     * @return
     */
    @Override
    public Map<Long, BaseOrganizationVO> mapByIds(Set<Long> ids) {
        Map<Long, BaseOrganizationVO> map = new HashMap<>(8);
        if (ids.isEmpty()) {
            return map;
        }
        List<BaseOrganizationVO> list = listById(ids);
        list.forEach(t -> {
            map.put(t.getId(), t);
        });
        return map;
    }

    /**
     * 批量code查询转map
     *
     * @param codes
     * @return
     */
    @Override
    public Map<Long, BaseOrganizationVO> mapByCodes(Set<String> codes) {
        Map<Long, BaseOrganizationVO> map = new HashMap<>(8);
        if (codes.isEmpty()) {
            return map;
        }
        List<BaseOrganizationVO> list = listByCode(codes);
        list.forEach(t -> {
            map.put(t.getId(), t);
        });
        return map;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeById(Serializable id) {
        BaseOrganizationEntity entity = getById(id);
        if (entity == null) {
            return false;
        }
        Set<Long> moveIds = new HashSet<>();
        moveIds.add(entity.getId());
        boolean flag = super.removeById(id);
        if (flag) {
            // 删除所有下级机构
            QueryWrapper<BaseOrganizationEntity> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(BaseOrganizationEntity::getParentId, id);
            // 移动下级的机构成员
            List<Long> subList = list(wrapper).stream().map(t -> t.getId()).collect(Collectors.toList());
            moveIds.addAll(subList);
            // 批量删除
            remove(wrapper);
        }
        // 删除机构后，机构成员将会自动移动到根机构下
        organizationUserService.moveOrgUser(moveIds, entity.getParentId());
        return flag;
    }

    @Override
    public boolean removeByIds(Collection<?> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return false;
        }
        boolean flag = super.removeByIds(idList);
        if (flag) {
            // 级联删除
            QueryWrapper<BaseOrganizationEntity> wrapper = new QueryWrapper<>();
            wrapper.lambda().in(BaseOrganizationEntity::getParentId, idList);
            remove(wrapper);
        }
        return flag;
    }


    private List<BaseOrganizationVO> buildOrganizationVoList(List<BaseOrganizationEntity> list) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.EMPTY_LIST;
        }
        Set<Long> userIds = list.stream().filter(t -> t.getHeadUserId() != null).map(t -> t.getHeadUserId()).collect(Collectors.toSet());
        Map<Long, BaseUserEntity> userMap = userService.mapByIds(userIds);
        List<BaseOrganizationVO> voList = list.stream().map(t -> {
            BaseOrganizationVO vo = new BaseOrganizationVO();
            BeanUtils.copyProperties(t, vo);
            BaseUserEntity baseUserEntity = userMap.get(t.getHeadUserId());
            if (baseUserEntity != null) {
                vo.setHeadUserFullName(baseUserEntity.getFullName());
                vo.setHeadUserNo(baseUserEntity.getUserNo());
            }
            return vo;
        }).collect(Collectors.toList());
        return voList;
    }

    private BaseOrganizationVO buildOrganizationVo(BaseOrganizationEntity entity) {
        if (entity == null) {
            return null;
        }
        List<BaseOrganizationEntity> list = new ArrayList<>();
        list.add(entity);
        List<BaseOrganizationVO> voList = buildOrganizationVoList(list);
        return voList.size() > 0 ? voList.get(0) : null;
    }
}
